package org.sylfra.idea.plugins.revu.ui.forms.settings.project;

import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.fileChooser.FileTextField;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.ui.DocumentAdapter;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.sylfra.idea.plugins.revu.RevuBundle;
import org.sylfra.idea.plugins.revu.RevuException;
import org.sylfra.idea.plugins.revu.business.ReviewManager;
import org.sylfra.idea.plugins.revu.model.Review;
import org.sylfra.idea.plugins.revu.model.ReviewStatus;
import org.sylfra.idea.plugins.revu.ui.statusbar.StatusBarComponent;
import org.sylfra.idea.plugins.revu.ui.statusbar.StatusBarMessage;
import org.sylfra.idea.plugins.revu.utils.ReviewFileChooser;
import org.sylfra.idea.plugins.revu.utils.RevuUtils;
import org.sylfra.idea.plugins.revu.utils.RevuVfsUtils;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.ResourceBundle;

public class CreateReviewDialog extends DialogWrapper
{
  /**
   * Method generated by IntelliJ IDEA GUI Designer
   * >>> IMPORTANT!! <<<
   * DO NOT edit this method OR call it in your code!
   *
   * @noinspection ALL
   */
  private void $$$setupUI$$$()
  {
    createUIComponents();
    contentPane = new JPanel();
    contentPane.setLayout(new BorderLayout(0, 0));
    final JPanel panel1 = new JPanel();
    panel1.setLayout(new GridLayoutManager(5, 3, new Insets(0, 0, 0, 0), 0, 0));
    contentPane.add(panel1, BorderLayout.CENTER);
    lbFile = new JLabel();
    lbFile.setFont(new Font(lbFile.getFont().getName(), Font.BOLD, lbFile.getFont().getSize()));
    this.$$$loadLabelText$$$(lbFile,
      ResourceBundle.getBundle("org/sylfra/idea/plugins/revu/resources/Bundle").getString("reviewForm.file.label"));
    panel1.add(lbFile, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_EAST, GridConstraints.FILL_NONE,
      GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
    tfFile.setColumns(0);
    panel1.add(tfFile, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
      GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(300, -1), null, 0,
      false));
    rbTypeBlank = new JRadioButton();
    rbTypeBlank.setSelected(true);
    this.$$$loadButtonText$$$(rbTypeBlank,
      ResourceBundle.getBundle("org/sylfra/idea/plugins/revu/resources/Bundle").getString(
        "projectSettings.review.importDialog.type.blank.text"));
    panel1.add(rbTypeBlank, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
      GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED,
      null, null, null, 0, false));
    bnFileChooser = new JButton();
    bnFileChooser.setMargin(new Insets(0, 0, 0, 0));
    bnFileChooser.setText("...");
    panel1.add(bnFileChooser,
      new GridConstraints(1, 2, 1, 1, GridConstraints.ANCHOR_SOUTHWEST, GridConstraints.FILL_NONE,
        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
    tfName = new JTextField();
    panel1.add(tfName, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
      GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0,
      false));
    final Spacer spacer1 = new Spacer();
    panel1.add(spacer1, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1,
      GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
    lbTitle = new JLabel();
    lbTitle.setEnabled(true);
    lbTitle.setFont(new Font(lbTitle.getFont().getName(), Font.BOLD, lbTitle.getFont().getSize()));
    this.$$$loadLabelText$$$(lbTitle,
      ResourceBundle.getBundle("org/sylfra/idea/plugins/revu/resources/Bundle").getString(
        "projectSettings.review.importDialog.name.text"));
    panel1.add(lbTitle, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_EAST, GridConstraints.FILL_NONE,
      GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
    final JPanel panel2 = new JPanel();
    panel2.setLayout(new GridLayoutManager(2, 2, new Insets(0, 0, 0, 0), 0, 0));
    panel1.add(panel2, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
      GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
      null, null, null, 0, false));
    rbTypeLink = new JRadioButton();
    this.$$$loadButtonText$$$(rbTypeLink,
      ResourceBundle.getBundle("org/sylfra/idea/plugins/revu/resources/Bundle").getString(
        "projectSettings.review.importDialog.type.link.text"));
    panel2.add(rbTypeLink, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
      GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
    cbReviewLink = new JComboBox();
    panel2.add(cbReviewLink, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
      GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
    rbTypeCopy = new JRadioButton();
    rbTypeCopy.setSelected(false);
    this.$$$loadButtonText$$$(rbTypeCopy,
      ResourceBundle.getBundle("org/sylfra/idea/plugins/revu/resources/Bundle").getString(
        "projectSettings.review.importDialog.type.copy.text"));
    panel2.add(rbTypeCopy, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
      GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(86, 22), null, 0, false));
    cbReviewCopy = new JComboBox();
    panel2.add(cbReviewCopy, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
      GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
    lbFile.setLabelFor(tfFile);
    lbTitle.setLabelFor(tfName);
    ButtonGroup buttonGroup;
    buttonGroup = new ButtonGroup();
    buttonGroup.add(rbTypeCopy);
    buttonGroup.add(rbTypeCopy);
    buttonGroup.add(rbTypeLink);
    buttonGroup.add(rbTypeBlank);
  }

  /**
   * @noinspection ALL
   */
  private void $$$loadLabelText$$$(JLabel component, String text)
  {
    StringBuffer result = new StringBuffer();
    boolean haveMnemonic = false;
    char mnemonic = '\0';
    int mnemonicIndex = -1;
    for (int i = 0; i < text.length(); i++)
    {
      if (text.charAt(i) == '&')
      {
        i++;
        if (i == text.length())
        {
          break;
        }
        if (!haveMnemonic && text.charAt(i) != '&')
        {
          haveMnemonic = true;
          mnemonic = text.charAt(i);
          mnemonicIndex = result.length();
        }
      }
      result.append(text.charAt(i));
    }
    component.setText(result.toString());
    if (haveMnemonic)
    {
      component.setDisplayedMnemonic(mnemonic);
      component.setDisplayedMnemonicIndex(mnemonicIndex);
    }
  }

  /**
   * @noinspection ALL
   */
  private void $$$loadButtonText$$$(AbstractButton component, String text)
  {
    StringBuffer result = new StringBuffer();
    boolean haveMnemonic = false;
    char mnemonic = '\0';
    int mnemonicIndex = -1;
    for (int i = 0; i < text.length(); i++)
    {
      if (text.charAt(i) == '&')
      {
        i++;
        if (i == text.length())
        {
          break;
        }
        if (!haveMnemonic && text.charAt(i) != '&')
        {
          haveMnemonic = true;
          mnemonic = text.charAt(i);
          mnemonicIndex = result.length();
        }
      }
      result.append(text.charAt(i));
    }
    component.setText(result.toString());
    if (haveMnemonic)
    {
      component.setMnemonic(mnemonic);
      component.setDisplayedMnemonicIndex(mnemonicIndex);
    }
  }

  /**
   * @noinspection ALL
   */
  public JComponent $$$getRootComponent$$$()
  {
    return contentPane;
  }

  public static enum ImportType
  {
    BLANK,
    COPY,
    LINK
  }

  private final Project project;
  private final boolean createMode;
  private ReviewFileChooser fileChooser;
  private JPanel contentPane;
  private JRadioButton rbTypeBlank;
  private JRadioButton rbTypeCopy;
  private JRadioButton rbTypeLink;
  private JComboBox cbReviewCopy;
  private JComboBox cbReviewLink;
  private JTextField tfName;
  private JTextField tfFile;
  private JButton bnFileChooser;
  private JLabel lbTitle;
  private JLabel lbFile;
  private FileTextField fileTextField;
  private Review currentReview;
  private String currentPath;

  public CreateReviewDialog(final Project project, boolean createMode)
  {
    super(project, false);
    this.project = project;
    this.createMode = createMode;

    $$$setupUI$$$();
    configureUI(createMode);
  }

  private void createUIComponents()
  {
    fileChooser = new ReviewFileChooser(project);
    fileTextField = FileChooserFactory.getInstance().createFileTextField(
      fileChooser.getDescriptor(), false, myDisposable);
    tfFile = fileTextField.getField();
    tfFile.setText(project.getBaseDir().getPath());
  }

  private void configureUI(boolean createMode)
  {
    bnFileChooser.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        VirtualFile defaultFile = (tfFile.getText().length() == 0)
          ? null : RevuVfsUtils.findFile(tfFile.getText());

        VirtualFile vFile = fileChooser.selectFileToSave(defaultFile);

        if (vFile != null)
        {
          tfFile.setText(vFile.getPath());
        }
      }
    });

    DefaultListCellRenderer comboRenderer = createComboReviewRenderer();
    cbReviewCopy.setRenderer(comboRenderer);
    cbReviewLink.setRenderer(comboRenderer);

    DocumentAdapter textFieldsListener = new DocumentAdapter()
    {
      public void textChanged(DocumentEvent event)
      {
        setOKActionEnabled((tfName.getText().trim().length() > 0)
          && (tfFile.getText().trim().length() > 0)
          && (fileTextField.getSelectedFile() != null)
          && (fileTextField.getSelectedFile().isDirectory()));
      }
    };
    tfName.getDocument().addDocumentListener(textFieldsListener);
    tfFile.getDocument().addDocumentListener(textFieldsListener);

    rbTypeBlank.setVisible(createMode);
    rbTypeBlank.setSelected(createMode);
    rbTypeCopy.setSelected(!createMode);
    lbTitle.setVisible(createMode);
    tfName.setVisible(createMode);
    lbFile.setVisible(createMode);
    tfFile.setVisible(createMode);
    bnFileChooser.setVisible(createMode);

    cbReviewCopy.setEnabled(!createMode);
    cbReviewLink.setEnabled(false);

    ActionListener radioTypeListener = new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cbReviewLink.setEnabled(rbTypeLink.isSelected());
        cbReviewCopy.setEnabled(rbTypeCopy.isSelected());
      }
    };
    rbTypeBlank.addActionListener(radioTypeListener);
    rbTypeCopy.addActionListener(radioTypeListener);
    rbTypeLink.addActionListener(radioTypeListener);

    setOKActionEnabled(!createMode);
    setTitle(RevuBundle.message(createMode
      ? "projectSettings.review.importDialog.create.title"
      : "projectSettings.review.importDialog.update.title"));

    init();
    pack();
  }

  private DefaultListCellRenderer createComboReviewRenderer()
  {
    return new DefaultListCellRenderer()
    {
      public Component getListCellRendererComponent(JList list, Object value, int index,
        boolean isSelected, boolean cellHasFocus)
      {
        value = ((Review) value).getName();
        return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
      }
    };
  }

  protected JComponent createCenterPanel()
  {
    return contentPane;
  }

  @Override
  public JComponent getPreferredFocusedComponent()
  {
    return createMode ? tfName : rbTypeCopy;
  }

  @NotNull
  public String getReviewName()
  {
    return tfName.getText();
  }

  @NotNull
  public String getReviewPath()
  {
    return currentPath;
  }

  @Nullable
  public Review getImportedReview()
  {
    if (rbTypeCopy.isSelected())
    {
      return (Review) cbReviewCopy.getSelectedItem();
    }

    if (rbTypeLink.isSelected())
    {
      return (Review) cbReviewLink.getSelectedItem();
    }

    return null;
  }

  public ImportType getImportType()
  {
    if (rbTypeCopy.isSelected())
    {
      return ImportType.COPY;
    }

    if (rbTypeLink.isSelected())
    {
      return ImportType.LINK;
    }

    return ImportType.BLANK;
  }

  public void show(@NotNull java.util.List<Review> currentReviews, @Nullable Review review)
  {
    currentReview = review;

    ReviewManager reviewManager = project.getComponent(ReviewManager.class);
    java.util.List<Review> reviews = new ArrayList<Review>(
      reviewManager.getReviews(currentReviews, null, ReviewStatus.DRAFT, ReviewStatus.FIXING, ReviewStatus.REVIEWING,
        ReviewStatus._TEMPLATE));

    CollectionComboBoxModel cbModel = new CollectionComboBoxModel(reviews, reviews.get(0));

    cbReviewCopy.setModel(cbModel);
    cbReviewLink.setModel(cbModel);

    super.show();
  }

  @Override
  protected void doOKAction()
  {
    ReviewManager reviewManager = project.getComponent(ReviewManager.class);

    // Update
    if (currentReview != null)
    {
      // Cyclic link
      Review importedReview = getImportedReview();
      if (importedReview != null)
      {
        try
        {
          reviewManager.checkCyclicLink(currentReview, importedReview);
        }
        catch (RevuException exception)
        {
          String errorTitle = RevuBundle.message("friendlyError.externalizing.cyclicReview.title.text");
          setErrorText(errorTitle);

          StatusBarComponent.showMessageInPopup(project, (new StatusBarMessage(StatusBarMessage.Type.ERROR, errorTitle,
            exception.getMessage())), false);
          return;
        }
      }
    }
    // Creation
    else
    {
      // Name already exists
      if (reviewManager.getReviewByName(tfName.getText()) != null)
      {
        setErrorText(RevuBundle.message("projectSettings.review.importDialog.nameAlreadyExists.text"));
        return;
      }
    }

    String fileName = RevuUtils.buildFileNameFromReviewName(getReviewName());
    VirtualFile vFile = fileTextField.getSelectedFile();

    // @TODO check vFile is null ?
    File file = new File(vFile.getPath(), fileName);
    currentPath = RevuVfsUtils.buildAbsolutePath(file);
    if (file.exists())
    {
      // Don't provide path as msg arg since error label height is fixed and is not appropriate for 2 lines
      setErrorText(RevuBundle.message("projectSettings.review.fileAlreadyExists.text"));
      return;
    }

    super.doOKAction();
  }

}
